package com.miao.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miao.base.exception.XueChengPlusException;
import com.miao.base.utils.QRCodeUtil;
import com.miao.config.AlipayConfig;
import com.miao.config.PayNotifyConfig;
import com.miao.dto.AddOrderDto;
import com.miao.dto.PayRecordDto;
import com.miao.dto.PayStatusDto;
import com.miao.mapper.XcOrdersGoodsMapper;
import com.miao.mapper.XcOrdersMapper;
import com.miao.mapper.XcPayRecordMapper;
import com.miao.po.*;
import com.miao.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Correlation;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<XcOrdersMapper, XcOrders> implements OrderService {
    @Autowired
    private XcOrdersMapper ordersMapper;
    @Autowired
    private OrderGoodService orderGoodService;
    @Autowired
    private XcPayRecordMapper payRecordMapper;
    @Autowired
    private PayRecordService recordService;
    @Autowired
    private OrderServiceImpl orderService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private MqMessageService mqMessageService;
    @Autowired
    private MqMessageHistoryService mqMessageHistoryService;

    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;
    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;

    //生成订单二维码
    @Transactional
    @Override
    public PayRecordDto creatCode(String uid, AddOrderDto addOrderDto) {
        //插入订单以及订单明细
        XcOrders xcOrders = saveOrder(uid, addOrderDto);
        //插入支付记录表（传给第三方支付服务的本地订单序列为支付记录表的支付记录号）
        XcPayRecord xcPayRecord = creatPayCord(xcOrders);
        //生成二维码
        String qrCode = null;
        try {
            //url要可以被模拟器访问到，url为下单接口(稍后定义)
            String qrcodeurl = "http://192.168.1.101:63030/orders/requestpay?payNo=%s";
            String url = String.format(qrcodeurl, xcPayRecord.getPayNo());
            qrCode = new QRCodeUtil().createQRCode(url, 200, 200);
        } catch (IOException e) {
            XueChengPlusException.cast("生成二维码出错");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(xcPayRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);

        return payRecordDto;

    }
    //查询订单结果，并更新订单状态
    @Override
    public PayRecordDto queryResult(String payNo) {
        //查询支付宝状态
        PayStatusDto payStatus = getPayStatus(payNo);
        //保存支付结果
        orderService.saveStatus(payStatus);
        //返回最新的支付信息
        XcPayRecord payRecordByPayno = recordService.getPayRecordByPayno(payNo);
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecordByPayno, payRecordDto);
        return payRecordDto;
    }
    //向消息队列发送通知
    @Override
    public void notifyResultToMq(MqMessage mqMessage) {
        Long id = mqMessage.getId();
        //设置回调方法
        CorrelationData correlationData = new CorrelationData(id.toString());
        correlationData.getFuture().addCallback(result->{
            if(result.isAck()){
                //发送成功，删除消息表中的数据
                mqMessageService.completed(id);
                MqMessageHistory mqMessageHistory = new MqMessageHistory();
                BeanUtils.copyProperties(mqMessage, mqMessageHistory);
                mqMessageHistoryService.save(mqMessageHistory);

            }else{
                //发送失败
                log.error("发送消息失败！");
            }
        }, ex->{
            log.error("发送消息异常！");
        });
        //发送消息
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT, "", mqMessage, correlationData);
    }

    //保存支付结果
    @Transactional
    public void saveStatus(PayStatusDto payStatusDto){
        //支付流水号
        String payNo = payStatusDto.getOut_trade_no();
        XcPayRecord payRecord = recordService.getPayRecordByPayno(payNo);
        if (payRecord == null) {
            XueChengPlusException.cast("支付记录找不到");
        }
        //拿到相关联的订单信息
        Long orderId = payRecord.getOrderId();
        XcOrders xcOrders = ordersMapper.selectById(orderId);
        if(xcOrders == null){
            XueChengPlusException.cast("订单记录找不到");
        }
        //若查到的已经支付成功，不用改
        String status = payRecord.getStatus();
        if(status.equals("601002")){
            //return;
        }
        //若支付宝信息为成功
        String trade_status = payStatusDto.getTrade_status();
        if(trade_status.equals("TRADE_SUCCESS")){
            //更新支付记录表
            payRecord.setStatus("601002");
            payRecord.setOutPayNo(payStatusDto.getTrade_no());//支付宝号
            payRecord.setOutPayChannel("AliPay");
            payRecord.setPaySuccessTime(LocalDateTime.now());
            payRecordMapper.updateById(payRecord);
            //更新订单表
            xcOrders.setStatus("600002");
            ordersMapper.updateById(xcOrders);
        }
        //向消息队列发送消息
        MqMessage mqMessage = mqMessageService.addMessage("payresult_notify", xcOrders.getOutBusinessId(), xcOrders.getOrderType(), null);
        if(mqMessage == null){
            System.out.println("fuck!");
        }
        notifyResultToMq(mqMessage);
    }
    //支付宝查询订单状态
    private PayStatusDto getPayStatus(String payNo){
        //========请求支付宝查询支付结果=============
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); //获得初始化的AlipayClient
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                XueChengPlusException.cast("请求支付查询查询失败");
            }
        } catch (AlipayApiException e) {
            log.error("请求支付宝查询支付结果异常:{}", e.toString(), e);
            XueChengPlusException.cast("请求支付查询查询失败");
        }

        //获取支付结果
        String resultJson = response.getBody();
        //转map
        Map resultMap = JSON.parseObject(resultJson, Map.class);
        Map alipay_trade_query_response = (Map) resultMap.get("alipay_trade_query_response");
        //支付结果
        String trade_status = (String) alipay_trade_query_response.get("trade_status");
        String total_amount = (String) alipay_trade_query_response.get("total_amount");
        String trade_no = (String) alipay_trade_query_response.get("trade_no");
        //保存支付结果
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_status(trade_status);
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTrade_no(trade_no);
        payStatusDto.setTotal_amount(total_amount);
        return payStatusDto;

    }
    //插入订单以及订单明细
    private XcOrders saveOrder(String uid, AddOrderDto addOrderDto){
        //插入订单表------------------------------------
        //幂等性判断
        XcOrders orderByBussinessId = getOrderByBussinessId(addOrderDto.getOutBusinessId());
        if(orderByBussinessId != null){
            return  orderByBussinessId;
        }
        orderByBussinessId = new XcOrders();
        //雪花算法生成id
        orderByBussinessId.setId(new util.SnowFlakeUtil().nextId());
        orderByBussinessId.setTotalPrice(addOrderDto.getTotalPrice());
        orderByBussinessId.setCreateDate(LocalDateTime.now());
        orderByBussinessId.setStatus("6000001");//未支付
        orderByBussinessId.setUserId(uid);
        orderByBussinessId.setOrderType("60201");//付费课程
        orderByBussinessId.setOrderName(addOrderDto.getOrderName());
        orderByBussinessId.setOrderDescrip(addOrderDto.getOrderDescrip());
        orderByBussinessId.setOrderDetail(addOrderDto.getOrderDetail());
        orderByBussinessId.setOutBusinessId(addOrderDto.getOutBusinessId());//记录选课表的主键
        int insert = ordersMapper.insert(orderByBussinessId);
        if(insert <= 0){
            XueChengPlusException.cast("插入订单失败！！！");
        }
        //插入订单明细---------------------------------------
        //订单明细就是orderDetails（JSON形式）[一个订单可能多个商品]
        String orderDetailJson = addOrderDto.getOrderDetail();
        List<XcOrdersGoods> xcOrdersGoods = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        for (XcOrdersGoods xcOrdersGood : xcOrdersGoods) {
            xcOrdersGood.setOrderId(orderByBussinessId.getId());
        }
        orderGoodService.saveBatch(xcOrdersGoods);

        return orderByBussinessId;

    }

    //插入支付表
    private XcPayRecord creatPayCord(XcOrders orders){
        //查看订单是否存在
        XcOrders xcOrders = ordersMapper.selectById(orders.getId());
        if(xcOrders == null){
            XueChengPlusException.cast("订单不存在！！！");
        }
        if(orders.getStatus().equals("601002")){
            XueChengPlusException.cast("订单已支付！！！");
        }
        XcPayRecord xcPayRecord = recordService.getOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getOrderId, xcOrders.getId()));
        if(xcPayRecord != null){
            return xcPayRecord;
        }
        xcPayRecord = new XcPayRecord();
        xcPayRecord.setPayNo(new util.SnowFlakeUtil().nextId());//传给支付宝的号
        xcPayRecord.setOrderId(orders.getId());
        xcPayRecord.setOrderName(orders.getOrderName());
        xcPayRecord.setTotalPrice(orders.getTotalPrice());
        xcPayRecord.setCurrency("CNY");
        xcPayRecord.setCreateDate(LocalDateTime.now());
        xcPayRecord.setStatus("601001");//未支付
        xcPayRecord.setUserId(orders.getUserId());
        int insert = payRecordMapper.insert(xcPayRecord);
        if(insert <= 0){
            XueChengPlusException.cast("支付表插入失败！");
        }
        return xcPayRecord;


    }



    //根据选课记录的id查询订单表，看是否已经创建过（一个选课记录【某个用户选的某一个课】只能创建一次订单）
    private XcOrders getOrderByBussinessId(String bussiness){
        return ordersMapper.selectOne(new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getOutBusinessId, bussiness));
    }
}
